// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//  * Redistributions of source code must retain the above copyright
//    notice, this list of conditions and the following disclaimer.
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in the
//    documentation and/or other materials provided with the distribution.
//  * Neither the name of NVIDIA CORPORATION nor the names of its
//    contributors may be used to endorse or promote products derived
//    from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Copyright (c) 2016-2023 NVIDIA Corporation. All rights reserved.

//! @file
//!
//! @brief Defines the API for the NvBlastExtTkEvent class

#ifndef NVBLASTTKEVENT_H
#define NVBLASTTKEVENT_H

#include <vector>

#include "NvBlastTypes.h"


namespace Nv
{
namespace Blast
{

// Forward declarations
class TkObject;
class TkActor;
class TkFamily;
class TkJoint;


/**
By the time events are dispatched, a specific TkActor may have been split and became invalid.
This structure caches the state before invalidation happened.
*/
struct TkActorData
{
    TkFamily*   family;     //!< TkFamily of the originating TkActor
    void*       userData;   //!< TkActor.userData of the originating TkActor
    uint32_t    index;      //!< TkActor::getIndex() of the originating TkActor
};


/**
Event data dispatched to TkEventListener objects.  The user may implement the abstract TkEventListener interface
and pass the listener object to a BlastTk object which dispatches events.  (See for example TkFamily.)
*/
struct TkEvent
{
    // Enums
    enum Type
    {
        Split,              //!< Sent when a TkActor is split.  See TkSplitEvent.
        FractureCommand,    //!< Sent when a TkActor generated fracture commands using TkActor::generateFracture.
        FractureEvent,      //!< Sent when a TkActor is fractured using TkActor::applyFracture.
        JointUpdate,        //!< Sent when TkJoints change their attachment state.  See TkJointUpdateEvent.

        TypeCount
    };

    // Data
    const void* payload;    //!< Type-dependent payload data
    Type        type;       //!< See the Type enum, above

    /**
    Casts the payload data into its type-dependent format.

    \return the payload for an event of type T
    */
    template<typename T>
    const T* getPayload() const { return reinterpret_cast<const T*>(payload); }
};


/**
Payload for TkEvent::Split events

When this event is sent, the parent TkActor that was split is no longer valid.  Therefore it is not referenced
directly in the event data.  Instead, its TkFamily, index within the TkFamily, and userData are stored.  In addition,
this event gives the child TkActors generated by the split.
*/
struct TkSplitEvent
{
    enum { EVENT_TYPE = TkEvent::Split };

    TkActorData parentData;     //!< The data of parent TkActor that was split
    uint32_t    numChildren;    //!< The number of children into which the parent TkActor was split
    TkActor**   children;       //!< An array of pointers to the children into which the TkActor was split
};


/**
Payload for the TkEvent::FractureCommand events

Fracture Commands used to apply fracture to a TkActor.
*/
struct TkFractureCommands
{
    enum { EVENT_TYPE = TkEvent::FractureCommand };

    TkActorData             tkActorData;    //!< The data of TkActor that received the fracture command
    NvBlastFractureBuffers  buffers;        //!< The fracture commands used to modify the TkActor
};


/**
Payload for the TkEvent::FractureEvent events

Fracture Events resulting from applying fracture to a TkActor.
*/
struct TkFractureEvents
{
    enum { EVENT_TYPE = TkEvent::FractureEvent };

    TkActorData             tkActorData;    //!< The data of TkActor that received the fracture command
    NvBlastFractureBuffers  buffers;        //!< The fracture result of the modified TkActor
    uint32_t                bondsDamaged;   //!< number of damaged bonds (health remains)
    uint32_t                bondsBroken;    //!< number of broken bonds (health exhausted)
    uint32_t                chunksDamaged;  //!< number of damaged chunks (health remains) including child chunks
    uint32_t                chunksBroken;   //!< number of broken chunks (health exhausted) including child chunks
};


/**
Payload for the TkEvent::JointUpdate events

Event type sent when a TkJoint's TkActor references change.  This may indicate a joint becoming external,
simply changing actors when split events occur on one or both of the actors, or when one or both of the actors
are destroyed.
*/
struct TkJointUpdateEvent
{
    enum { EVENT_TYPE = TkEvent::JointUpdate };

    enum Subtype
    {
        External,       //!< A joint that used to be internal to a single TkActor now joins two different TkActors
        Changed,        //!< One or both of the joint's attached TkActors has changed.  The previous TkActors were distinct, however, differentiating this from the JointExternal case
        Unreferenced    //!< The joint's actors have been set to NULL.  The joint will not be used again, and the user may release the TkJoint at this time
    };

    TkJoint*    joint;      //!< The joint being updated
    Subtype     subtype;    //!< The type of update event this is (see Subtype)
};


/**
Interface for a listener of TkEvent data.  The user must implement this interface and pass it
to the object which will dispatch the events.
*/
class TkEventListener
{
public:
    /**
    Interface to be implemented by the user.  Events will be sent by BlastTk through a call to this function.

    \param[in]  events      The array of events being dispatched.
    \param[in]  eventCount  The number of events in the array.
    */
    virtual void    receive(const TkEvent* events, uint32_t eventCount) = 0;
};

} // namespace Blast
} // namespace Nv


#endif // ifndef NVBLASTTKEVENT_H
